16

相关知识

HTTP/HTTPS 是什么?

简单来说,HTTP 是一个传输网页内容的协议,比如我们浏览一个网页,网页上的文字、图片、 CSS 、 JS 等文件都是通过 HTTP 协议传输到我们的浏览器,然后被我们看到。因为 HTTP 是明文传输的,通过 HTTP 协议传输的内容很容易被偷看和篡改,为了安全(你肯定不想被人偷看或者篡改网页内容吧,比如网站银行密码什么的。)就为 HTTP 协议再加上了一层 SSL/TLS 安全协议,所以就有了 HTTPS 。

SSL/TLS 是什么?

SSL 是指安全套接字层(Secure Sockets Layer),内心纯洁的同学也可以理解为「带安全套的 HTTP」,因为带了安全套,所以当然会比较安全。TLS 是 传输层安全协议(Transport Layer Security),SSL 和 TLS 是同一个东西的不同阶段,理解为同一个东西也行,都是安全协议就对了。

为什么要部署 HTTPS?

说到底,就是 HTTPS 更安全。甚至为了安全,一个专业可靠的网站, HTTPS 是必须的。 Firefox 和 Chrome 都计划将没有配置 SSL 加密的 HTTP 网站标记为不安全,目前它们也正在联合其他相关的基金会与公司推动整个互联网 HTTPS 化,现在大家访问的一些主要的网站。如 Google 多年前就已经全部启用 HTTPS ,国内的淘宝、搜狗、知乎、百度等等也全面 HTTPS 了。甚至 Google 和百度的搜索结果也正在给予 HTTPS 的网站更高的排名和优先收录权。

怎么部署 HTTPS 呢?

你只需要有一张被信任的 CA ( Certificate Authority )也就是证书授权中心颁发的 SSL 安全证书,并且将它部署到你的网站服务器上。一旦部署成功后,当用户访问你的网站时,浏览器会在显示的网址前加一把小绿锁,表明这个网站是安全的,当然同时你也会看到网址前的前缀变成了 HTTPS ,不再是 HTTP 了。

怎么获得 SSL 安全证书呢?

理论上,我们自己也可以签发 SSL 安全证书,但是我们自己签发的安全证书不会被主流的浏览器信任,所以我们需要被信任的证书授权中心( CA )签发的安全证书。而一般的 SSL 安全证书签发服务都比较贵,比如 Godaddy 、 GlobalSign 等机构签发的证书一般都需要20美金一年甚至更贵,不过为了加快推广 HTTPS 的普及, EEF 电子前哨基金会、 Mozilla 基金会和美国密歇根大学成立了一个公益组织叫 ISRG ( Internet Security Research Group ),这个组织从 2015 年开始推出了 Let’s Encrypt 免费证书。这个免费证书不仅免费,而且还相当好用,所以我们就可以利用 Let’s Encrypt 提供的免费证书部署 HTTPS 了。

Let’s Encrypt 简介

前面已经介绍过, Let’s Encrypt 是 一个叫 ISRG ( Internet Security Research Group ,互联网安全研究小组)的组织推出的免费安全证书计划。参与这个计划的组织和公司可以说是互联网顶顶重要的先驱,除了前文提到的三个牛气哄哄的发起单位外,后来又有思科(全球网络设备制造商执牛耳者)、 Akamai 加入,甚至连 Linux 基金会也加入了合作,这些大牌组织的加入保证了这个项目的可信度和可持续性。

Certbot 简介

ISRG 的发起者 EFF (电子前哨基金会)为 Let’s Encrypt 项目发布了一个官方的客户端 Certbot ,利用它可以完全自动化的获取、部署和更新安全证书。虽然第三方工具也可以使用,但是官方工具更权威,风险也更小,而且遇到问题也更容易解决,毕竟有官方的支持。

实际操作

Certbot 使用方法

Certbot 的官网是https://certbot.eff.org/, 我们打开这个链接,选择自己使用的 web server 和操作系统。选择完之后,官网就会显示出对应的安装操作步骤。
以目前我所使用的服务器为例,web server 使用Nginx(1.12),操作系统是CentOS(7.3)。因为 Certbot 打包在EPEL中,所以在安装 Certbot 之前要先安装EPEL

yum -y install epel-release

然后按着官网给出的步骤提示命令安装 Certbot

yum install python2-certbot-nginx

安装完毕后,继续输入官网提示命令

certbot --nginx

运行此命令会自动获取证书,并且 Certbot 会自动编辑Nginx配置文件配置HTTPS服务。

这边在运行配置命令时遇到一个坑
ImportError: No module named 'requests.packages.urllib3'

可以看出是缺少一个模块包,看配置命令在命令台的输出,Certbot 是用 python 来写 Nginx 配置。既然是用的 python,可以通过 pip list 命令查看 python 的依赖包列表。但是查看是已经存在的,这个问题很快通过 Certbot 在 github 上的一个 Issues 找到了答案(Issues链接)。目前看是包的版本依赖有问题,执行以下命令进行依赖包的重装

pip uninstall requests
pip uninstall urllib3
yum remove python-urllib3
yum remove python-requests
yum install python-urllib3
yum install python-requests
yum install certbot

再次执行 certbot --nginx 命令成功。命令执行后首先会提示输入一个邮箱地址,主要作用是订阅一些通知,输入后回车。

[root@izuf6fco0zwyipdq9485s2z ~]# certbot --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx

▽
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): demo@mail.com // 演示邮箱
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

回车后 Certbot 就会自动请求下载 Let's Encrypt 证书,并设置 Nginx 配置文件。期间会有一些同意相关协议和选择哪个网站配置的交互,这个看输出文字就能明白意思。

...
▽
server {
(A)gree/(C)ancel: a

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
Starting new HTTPS connection (1): supporters.eff.org

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: kisstime.top
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for kisstime.top
Cleaning up challenges
...
但是这边到 Certbot 设置 Nginx 配置文件的时候遇到一个坑,报如下一个错误
An unexpected error occurred:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 2: ordinal not in range(128)
Please see the logfiles in /var/log/letsencrypt for more details.

熟悉 python 的同学应该对这个错误比较了解。不过博主 python 还是用的比较少,花了点时间了解了一下。

在解决错误之前,首先要了解unicode和utf-8的区别。unicode指的是万国码,是一种“字码表”。而utf-8是这种字码表储存的编码方法。unicode不一定要由utf-8这种方式编成bytecode储存,也可以使用utf-16,utf-7等其他方式。目前大多都以utf-8的方式来变成bytecode。其次,Python中字符串类型分为byte string 和 unicode string两种。如果在python文件中指定编码方式为utf-8(#coding=utf-8),那么所有带中文的字符串都会被认为是utf-8编码的byte string(例如:mystr="你好"),但是在函数中所产生的字符串则被认为是unicode string。问题就出在这边,unicode string 和 byte string 是不可以混合使用的,一旦混合使用了,就会产生这样的错误。例如:
self.response.out.write("你好"+self.request.get("argu"))
其中,"你好"被认为是byte string,而self.request.get("argu")的返回值被认为是unicode string。由于预设的解码器是ascii,所以就不能识别中文byte string。然后就报错了。

那理解了这个错误原因后,我这边首先想到的就是网站的 Nginx 配置文件中是否含有中文。打开一看,确实存在中文注释。将注释去掉,重新执行命令成功不在报错

接着命令交互会提示是否将所有HTTP重定向到HTTPS,我这边选择全部重定向也就是「2」。

Cleaning up challenges
Deploying Certificate to VirtualHost:  //这边会显示你的网站配置文件目录

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in //这边会显示你的网站配置文件目录

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://kisstime.top

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=kisstime.top
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   .../fullchain.pem
   Your key file has been saved at:
   .../privkey.pem
   Your cert will expire on 2019-02-14. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

OK,当完成上面最后一步后,输入如上信息后就表明 HTTPS 配置成功了!我们可以通过提示中的 SSL Server Test 网址来测试网站是否能够 HTTPS 来进行访问

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=kisstime.top

事实证明,高兴的太早了。。。通过测试网站和直接访问域名发现网站都是访问不了。思考了一下,确认下服务器的443端口是否开启,我这边用的是阿里云的服务器,登录控制台查看安全组规则,发现确实是443端口没有开启,配置开启后,重新访问成功。

其他

Nginx的设置说明

基本上 Certbot 会在对应的 Nginx 配置文件加上下面的参数:

server {
    # ... other configs
    
    # SSL 设置
    listen 443 ssl;

    # set crt and key
    ssl_certificate .../fullchain.pem;
    ssl_certificate_key .../privkey.pem;
    
    # include 基本的 ssl 设置
    include .../options-ssl-nginx.conf;
    
    # Certbot 也会生成一把 Diffie-Hellman 密钥
    ssl_dhparam .../ssl-dhparams.pem;

    # ... other configs
}

自动更新证书

Let’s Encrypt 免费SSL证书用起来非常方便,但每次申请只有三个月有效期,在每次到期之前都需要重新申请,Certbot 已经提供了一键续订的命令

certbot renew

我们可以通过添加此条命令的cron作业(或systemd计时器)来安排证书的自动续订

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin

0 0,12 * * * certbot renew --quiet 

Certbot 的 log 路径

Certbot 的 log 预设路径在 /var/log/letsencrypt,有需要可以去确认查看。

相关第三方

certbot-auto是对脚本certbot的封装,可以设置系统环境或自动升级。

参考资料

牛顿曾经说过:如果说我看得比别人更远些,那是因为我站在巨人的肩膀上。(If I have seen further, it is by standing on the shoulders of giants.)感谢。

博客原文链接

原文链接


Vick
76 声望218 粉丝

一个脱离高级趣味的程序员